/*
 * Copyright © OpenAtom Foundation.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *     http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package io.iec.edp.caf.databaseobject.common;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.*;
import com.zaxxer.hikari.HikariDataSource;
import io.iec.edp.caf.commons.utils.InvokeService;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import io.iec.edp.caf.databaseobject.api.entity.*;
import io.iec.edp.caf.databaseobject.api.exception.DboException;
import io.iec.edp.caf.databaseobject.common.database.GspDatabase;
import io.iec.edp.caf.databaseobject.common.database.GspDbFactory;
import io.seata.rm.datasource.DataSourceProxy;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.engine.jdbc.connections.spi.AbstractDataSourceBasedMultiTenantConnectionProviderImpl;
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
import org.hibernate.internal.ContextualJdbcConnectionAccess;
import org.hibernate.internal.SessionImpl;
import org.springframework.util.StringUtils;

import javax.persistence.EntityManager;
import java.io.IOException;
import java.lang.reflect.Field;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author liu_wei
 */
@Slf4j
public class DatabaseObjectCommonUtil {
    private static List<String> languages;
    public static boolean isToolEntrance = false;

    public final AbstractDatabaseObject deserialze(String content) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        //出现换行符会报错，需要处理
        mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
        JsonNode rootNode = null;
        try {
            rootNode = mapper.readTree(content);
        } catch (IOException e) {
            throw new RuntimeException("反序列化数据库对象报错：" + content, e);
        }
        int type = 0;
        if (rootNode.get("Type") == null) {
            if(rootNode.get("type") == null)
            {
                throw new RuntimeException("获取类型出错：" + content);
            }
            type = rootNode.get("type").asInt();
        }
        else
        {
            type = rootNode.get("Type").asInt();
        }

        if (type == DatabaseObjectType.Table.getValue()) {
            return deserialze(DatabaseObjectType.Table, content);
        } else if (type == DatabaseObjectType.View.getValue()) {
            return deserialze(DatabaseObjectType.View, content);
        } else if (type == DatabaseObjectType.TempTable.getValue()) {
            return deserialze(DatabaseObjectType.TempTable, content);
        } else {
            throw new RuntimeException("数据库对象类型不正确");
        }

    }

    public final AbstractDatabaseObject deserialze(DatabaseObjectType type, String content) throws IOException {
        AbstractDatabaseObject databaseObject;

        ObjectMapper mapper = new ObjectMapper();
        //出现换行符会报错，需要处理
        mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
        mapper.setPropertyNamingStrategy(PropertyNamingStrategy.UPPER_CAMEL_CASE);
        mapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        if (type == DatabaseObjectType.Table) {
            databaseObject = mapper.readValue(content, DatabaseObjectTable.class);
        } else if (type == DatabaseObjectType.View) {
            databaseObject = mapper.readValue(content, DatabaseObjectView.class);
        } else if (type == DatabaseObjectType.TempTable) {
            databaseObject = mapper.readValue(content, DatabaseObjectTempTable.class);
        } else {
            throw new RuntimeException(String.format("数据库对象类型不正确，请确认。"));
        }

        return databaseObject;
    }

    public final String serialze(AbstractDatabaseObject databaseObject) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        mapper.setPropertyNamingStrategy(PropertyNamingStrategy.UPPER_CAMEL_CASE);
        String oNodeStr = mapper.writeValueAsString(databaseObject);
        return oNodeStr;
    }

    /**
     * 对比新、旧Dbo的增量变化信息
     *
     * @return
     */
    public DboTableChangeInfo getDboTableChangeInfo(AbstractDatabaseObject newDatabaseObject, AbstractDatabaseObject oldDatabaseObject) {
        DboTableChangeInfo dboTableChangeInfo = new DboTableChangeInfo();
        DatabaseObjectTable newTable = (DatabaseObjectTable) newDatabaseObject;
        DatabaseObjectTable oldTable = (DatabaseObjectTable) oldDatabaseObject;
        if (!newTable.getCode().equalsIgnoreCase(oldTable.getCode())) {
            throw new DboException("数据库对象编号不允许修改，当前DBO编号为" + newTable.getCode() + ",原DBO编号为" + oldTable.getCode());
        }
        //增加、修改的列
        List<DatabaseObjectColumn> newTableColumns = newTable.getColumns();
        List<DatabaseObjectColumn> oldTableColumns = oldTable.getColumns();
        List<DatabaseObjectColumn> addedColumns = new ArrayList<>();
        List<DatabaseObjectColumn> changedColumns = new ArrayList<>();
        List<ColumnChangeOperation> changedColumnOperations = new ArrayList<>();
        DatabaseObjectColumn oldColumn = null;
        ColumnChangeOperation columnChangeOperation = null;

        //增加的多语列(放到前面，为了后续判断列修改，非多语修改成多语也是一种变化)
        dboTableChangeInfo.setNewMulityLanguageColumns(getAddedLanguageColumns(newTable, oldTable));

        for (DatabaseObjectColumn column : newTableColumns) {
            oldColumn = existsColumn(column, oldTableColumns);
            if (oldColumn != null) {
                columnChangeOperation = new ColumnChangeOperation();
                //对比新、老列是否一致
                if (!compareColumns(column, oldColumn, columnChangeOperation, newTable.getCode())) {
                    if (!checkDataTypeCompatibleForAllDB(column, oldColumn)) {
                        throw new DboException("类型修改不兼容，表编号:" + newTable.getCode() + "列编号:" + column.getCode() + "当前类型:" + oldColumn.getDataTypeStr() + "目标类型：" + column.getDataTypeStr());
                    }
                    changedColumnOperations.add(columnChangeOperation);
                    changedColumns.add(column);
                }
                //对比是否修改了多语(不包含新增的多语字段)
                if (dboTableChangeInfo.getNewMulityLanguageColumns() != null) {
                    for (String languageColumn : dboTableChangeInfo.getNewMulityLanguageColumns()) {
                        if (languageColumn.equalsIgnoreCase(oldColumn.getId()) && !changedColumns.contains(column)) {
                            changedColumns.add(column);
                        }
                    }
                }
                continue;
            }
            addedColumns.add(column);
        }
        if (addedColumns.size() > 0) {
            dboTableChangeInfo.setAddedColumn(addedColumns);
        }
        if (changedColumns.size() > 0) {
            dboTableChangeInfo.setChangedColumn(changedColumns);
            dboTableChangeInfo.setChangedColumnOperations(changedColumnOperations);
        }
        //新加的索引
        List<DatabaseObjectIndex> newTableIndex = newTable.getIndexes();
        List<DatabaseObjectIndex> oldTableIndex = oldTable.getIndexes();
        if (newTableIndex != null && newTableIndex.size() > 0) {
            if (oldTableIndex == null || oldTableIndex.size() == 0) {
                dboTableChangeInfo.setAddedIndex(newTableIndex);
            } else {
                List<DatabaseObjectIndex> addedIndexs = new ArrayList<>();
                List<DatabaseObjectIndex> changedIndexs = new ArrayList<>();
                DatabaseObjectIndex oldIndex = null;
                for (DatabaseObjectIndex index : newTableIndex) {
                    oldIndex = existsIndex(index, oldTableIndex);
                    if (oldIndex != null) {
                        //对比新、老索引是否一致
                        if (!compareIndexs(index, oldIndex)) {
                            changedIndexs.add(index);
                        }
                        continue;
                    }
                    addedIndexs.add(index);
                }
                if (addedIndexs.size() > 0) {
                    dboTableChangeInfo.setAddedIndex(addedIndexs);
                }
                if (changedIndexs.size() > 0) {
                    dboTableChangeInfo.setChangedIndex(changedIndexs);
                }
            }
        }
        //Dbo表命名规则
        if (!oldTable.getHasNameRule()) {
            dboTableChangeInfo.setDboTableNameRule(newTable.getDboTableNameRule());
        } else if (oldTable.getHasNameRule() && !newTable.getHasNameRule()) {
            throw new DboException("DBO表名规则不能移除，DBO编号为" + newTable.getCode());
        } else {
            DBOTableNameRule newTableNameRule = newTable.getDboTableNameRule();
            DBOTableNameRule oldTableNameRule = oldTable.getDboTableNameRule();
            if (!newTableNameRule.getId().equals(oldTableNameRule.getId()) ||
                    !newTableNameRule.getCode().equals(oldTableNameRule.getCode())
                    || !compareRuleStrategy(newTableNameRule.getDimensionStrategyWithOrder(), oldTableNameRule.getDimensionStrategyWithOrder())) {
                throw new DboException("DBO表名规则不允许修改，DBO编号为" + newTable.getCode());
            }
        }


        //同步历史表
        if ((newTable.isSynHis() == oldTable.isSynHis()) || newTable.isSynHis()) {
            dboTableChangeInfo.setSynHis(newTable.isSynHis());
        } else {
            throw new DboException("是否同步历史表不能由启用改为不启用，DBO编号为" + newTable.getCode());
        }
        //启动时间戳
        if ((newTable.isUsingTimeStamp() == oldTable.isUsingTimeStamp()) || newTable.isUsingTimeStamp()) {
            dboTableChangeInfo.setUsingTimeStamp(newTable.isUsingTimeStamp());
        } else {
            throw new DboException("是否启用时间戳字段不能由启用改为不启用，DBO编号为" + newTable.getCode());
        }

        dboTableChangeInfo.setVersion(newTable.getVersion());
        dboTableChangeInfo.setI18nObject(newTable.isI18NObject());
        dboTableChangeInfo.setName(newTable.getName());
        //主键名称是否变化
        dboTableChangeInfo.setPkName(newTable.getPkName());
        //主键列
        dboTableChangeInfo.setPrimaryKey(newTable.getPrimaryKey());
        //描述
        dboTableChangeInfo.setDescription(newTable.getDescription());
        return dboTableChangeInfo;
    }

    /**
     * 获取新增的多语列id列表
     *
     * @param newTable 新DBO
     * @param oldTable 老DBO
     * @return 新增的多语列id列表
     */
    private List<String> getAddedLanguageColumns(DatabaseObjectTable newTable, DatabaseObjectTable oldTable) {
        List<String> newLanguageColumns = newTable.getMultiLanguageColumns();
        List<String> oldLanguageColumns = oldTable.getMultiLanguageColumns();
        //使用code作为标识后
        Map<String, String> newLanguageColumnCodes = newTable.getMultiLanguageColumnCodes();
        List<String> newLanguageCodeList = new ArrayList<>(newLanguageColumnCodes.values());
        Map<String, String> oldLanguageColumnCodes = oldTable.getMultiLanguageColumnCodes();
        List<String> oldLanguageCodeList = new ArrayList<>(oldLanguageColumnCodes.values());
        if (newLanguageColumns != null && newLanguageColumns.size() > 0) {
            if (oldLanguageColumns == null || oldLanguageColumns.size() == 0) {
                return newLanguageColumns;
            } else {
                List<String> addedLanguageColumns = new ArrayList<>();
                for (String languageColumn : newLanguageColumns) {
                    if (oldLanguageColumns.contains(languageColumn) || oldLanguageCodeList.contains(newLanguageColumnCodes.get(languageColumn))) {
                        continue;
                    }
                    addedLanguageColumns.add(languageColumn);
                }
                for (String oldLanguageColumn : oldLanguageColumns) {
                    if (!newLanguageColumns.contains(oldLanguageColumn) && !newLanguageCodeList.contains(oldLanguageColumnCodes.get(oldLanguageColumn))) {
                        throw new DboException("字段不能由启用多语改为不启用，DBO编号为：" + newTable.getCode() + "字段ID为" + oldLanguageColumn);
                    }
                }
                return addedLanguageColumns;
            }
        }
        return new ArrayList<>();
    }

    /**
     * 合并Dbo增量，返回合并后的完整Dbo
     *
     * @param dboTableChangeInfo 增量
     * @param databaseObject     待合并的Dbo
     * @return
     */
    public AbstractDatabaseObject mergeDboIncrement(DboTableChangeInfo dboTableChangeInfo, AbstractDatabaseObject databaseObject, AbstractDatabaseObject newDatabaseObject) {
        DatabaseObjectTable databaseObjectTable = (DatabaseObjectTable) databaseObject;
        DatabaseObjectTable newDatabaseObjectTable = (DatabaseObjectTable) newDatabaseObject;
        List<DatabaseObjectColumn> addedColumn = dboTableChangeInfo.getAddedColumn();
        //新增的列
        if (addedColumn != null && addedColumn.size() > 0) {
            List<DatabaseObjectColumn> oldColumns = databaseObjectTable.getColumns();
            for (DatabaseObjectColumn column : addedColumn) {
                List<DatabaseObjectColumn> columns = oldColumns.stream().filter((item) -> item.getCode().equals(column.getCode())).collect(Collectors.toList());
                for (DatabaseObjectColumn oldColumn : columns) {
                    oldColumns.remove(oldColumn);
                }
            }
            databaseObjectTable.getColumns().addAll(addedColumn);
        }
        //修改的列
        List<DatabaseObjectColumn> changedColumn = dboTableChangeInfo.getChangedColumn();
        List<DatabaseObjectColumn> oldColumns = databaseObjectTable.getColumns();
        DatabaseObjectColumn oldColumn = null;
        if (changedColumn != null && changedColumn.size() > 0) {
            for (DatabaseObjectColumn column : changedColumn) {
                for (int i = 0; i < oldColumns.size(); i++) {
                    if (oldColumns.get(i).getId().equals(column.getId()) || oldColumns.get(i).getCode().equals(column.getCode())) {
                        oldColumns.set(i, column);
                    }
                }
            }
        }
        //增加的索引
        List<DatabaseObjectIndex> addedIndex = dboTableChangeInfo.getAddedIndex();
        if (addedIndex != null && addedIndex.size() > 0) {
            if (databaseObjectTable.getIndexes() != null) {
                databaseObjectTable.getIndexes().addAll(addedIndex);
            } else {
                databaseObjectTable.setIndexes(addedIndex);
            }
        }
        //修改的索引
        List<DatabaseObjectIndex> oldIndexs = databaseObjectTable.getIndexes();
        List<DatabaseObjectIndex> changedIndex = dboTableChangeInfo.getChangedIndex();
        DatabaseObjectIndex oldIndex = null;
        if (oldIndexs != null && changedIndex != null && changedIndex.size() > 0) {
            for (DatabaseObjectIndex index : changedIndex) {
                oldIndex = existsIndex(index, oldIndexs);
                oldIndexs.remove(oldIndex);
                oldIndexs.add(index);
            }
        }
        if (dboTableChangeInfo.getDboTableNameRule() != null) {
            databaseObjectTable.setDboTableNameRule(dboTableChangeInfo.getDboTableNameRule());
        }
        //根据getDboTableChangeInfo方法里的多语判断是否合理，默认多语不能由启用改为不启用，所以通过检查后以新DBO里的多语列为标准即可
        databaseObjectTable.setMultiLanguageColumns(newDatabaseObjectTable.getMultiLanguageColumns());
//        List<String> newLanguageColumns = dboTableChangeInfo.getNewMulityLanguageColumns();
//        if (newLanguageColumns != null && newLanguageColumns.size() > 0) {
//            databaseObjectTable.getMultiLanguageColumns().addAll(newLanguageColumns);
//        }
        databaseObjectTable.setName(dboTableChangeInfo.getName());
        databaseObjectTable.setSynHis(dboTableChangeInfo.isSynHis());
        databaseObjectTable.setUsingTimeStamp(dboTableChangeInfo.isUsingTimeStamp());
        databaseObjectTable.setPkName(dboTableChangeInfo.getPkName());
        databaseObjectTable.setPrimaryKey(dboTableChangeInfo.getPrimaryKey());
        databaseObjectTable.setDescription(dboTableChangeInfo.getDescription());
        databaseObjectTable.setI18NObject(dboTableChangeInfo.isI18nObject());
        databaseObjectTable.setVersion(dboTableChangeInfo.getVersion());
        return databaseObjectTable;
    }

    /**
     * 判断某一列，在列集合中是否存在,并反馈存在的列对象
     *
     * @param column
     * @param columns
     * @return
     */
    private DatabaseObjectColumn existsColumn(DatabaseObjectColumn column, List<DatabaseObjectColumn> columns) {
        for (DatabaseObjectColumn col : columns) {
            if (col.getId().equals(column.getId()) || col.getCode().equals(column.getCode())) {
                return col;
            }
        }
        return null;
    }


    /**
     * 对比两个列是否一致
     *
     * @param column
     * @param oldColumn
     * @return
     */
    private boolean compareColumns(DatabaseObjectColumn column, DatabaseObjectColumn oldColumn, ColumnChangeOperation columnChangeOperation, String dboCode) {
        if (!column.getCode().equalsIgnoreCase(oldColumn.getCode())) {
            throw new DboException("数据库对象字段编号不允许调整，请确认。当前DBO编号为" + dboCode + ";当前字段编号为" + column.getCode() + ",原有字段编号为" + oldColumn.getCode());
        }
        boolean isColEquals = true;
        columnChangeOperation.setColumn(oldColumn);
        List<ColumnOperation> columnOperations = new ArrayList<>();
        columnChangeOperation.setOperations(columnOperations);
        ColumnOperation columnOperation = null;
        if (!compareStr(column.getId(), oldColumn.getId())) {
            isColEquals = false;
        }
        if (!compareStr(column.getName(), oldColumn.getName())) {
            isColEquals = false;
        }
        if (!compareStr(column.getDescription(), oldColumn.getDescription())) {
            isColEquals = false;
        }
        if (column.getDataType() != oldColumn.getDataType()) {
            columnOperation = new ColumnOperation();
            columnOperation.setOperationType(1);
            columnOperation.setOldValue(oldColumn.getDataType());
            columnOperation.setNewValue(column.getDataType());
            columnOperations.add(columnOperation);
            isColEquals = false;
        }
        if (column.getLength() < oldColumn.getLength()) {
            log.warn("检测到字段长度减小的逆向操作，已忽略！" + "当前DBO编号为" + dboCode + ";当前字段编号为" + column.getCode() + ",原有字段长度为" + oldColumn.getLength() + ",当前字段长度为" + column.getLength());
        }
        if (column.getLength() > oldColumn.getLength()) {
            columnOperation = new ColumnOperation();
            columnOperation.setOperationType(2);
            columnOperation.setOldValue(oldColumn.getLength());
            columnOperation.setNewValue(column.getLength());
            columnOperations.add(columnOperation);
            isColEquals = false;
        }
        if (column.getPrecision() != oldColumn.getPrecision() || column.getScale() != oldColumn.getScale()) {
            if (((oldColumn.getPrecision() - oldColumn.getScale()) > (column.getPrecision() - column.getScale())) || oldColumn.getScale() > column.getScale() || oldColumn.getPrecision() > column.getPrecision()) {
                log.warn("检测到字段精度减小的逆向操作，已忽略！" + "当前DBO编号为" + dboCode + ";当前字段编号为" + column.getCode() + ",原有字段长度为" + "(" + oldColumn.getPrecision() + "," + oldColumn.getScale() + ")" + ",当前字段长度为" + "(" + column.getPrecision() + "," + column.getScale() + ")");
            } else {
                columnOperation = new ColumnOperation();
                columnOperation.setOperationType(2);
                columnOperation.setOldValue(oldColumn.getPrecision() + "," + oldColumn.getScale());
                columnOperation.setNewValue(column.getPrecision() + "," + column.getScale());
                columnOperations.add(columnOperation);
                isColEquals = false;
            }
        }

        if (!compareStr(column.getDefaultValue(), oldColumn.getDefaultValue())) {
            if (StringUtils.hasText(column.getDefaultValue())) {
                columnOperation = new ColumnOperation();
                columnOperation.setOperationType(3);
                columnOperation.setOldValue(oldColumn.getDefaultValue());
                columnOperation.setNewValue(column.getDefaultValue());
                columnOperations.add(columnOperation);
            }
            isColEquals = false;
        }
        if (column.isIfPrimaryKey() != oldColumn.isIfPrimaryKey()) {
            isColEquals = false;
        }
        if (column.isNullable() != oldColumn.isNullable()) {
            isColEquals = false;
        }
        if (column.isUnique() != oldColumn.isUnique()) {
            isColEquals = false;
        }
        if (!compareStr(column.getUcName(), oldColumn.getUcName())) {
            isColEquals = false;
        }
        if (!compareStr(column.getDescription(), oldColumn.getDescription())) {
            isColEquals = false;
        }
        if (!compareStr(column.getVersion(), oldColumn.getVersion())) {
            isColEquals = false;
        }
        return isColEquals;
    }

    private boolean checkDataTypeCompatibleForAllDB(DatabaseObjectColumn column, DatabaseObjectColumn oldColumn) {

        //2020-08-31为了兼容产品部MySQL改造，去除字段长度比较，长度缩减不支持，长度增加需要判断实体表长度
        if (oldColumn.getDataType() == column.getDataType()) {
            return true;
        }

        if (oldColumn.getDataType() == DataType.Int) {
            if ((column.getDataType() == DataType.Decimal && column.getPrecision() - column.getScale() >= 10 && column.getPrecision() > 0 && column.getPrecision() <= 38 && column.getScale() >= 0)) {
                return true;
            }
        }

        if (oldColumn.getDataType() == DataType.Varchar) {
            if (column.getDataType() == DataType.Char || column.getDataType() == DataType.NChar || column.getDataType() == DataType.NVarchar) {
                return true;
            }
        }

        if (oldColumn.getDataType() == DataType.Char) {
            if (column.getDataType() == DataType.Varchar || column.getDataType() == DataType.NChar || column.getDataType() == DataType.NVarchar) {
                return true;
            }
        }
        if (oldColumn.getDataType() == DataType.NVarchar) {
            if (column.getDataType() == DataType.NChar) {
                return true;
            }
        }
        if (oldColumn.getDataType() == DataType.NChar) {
            if (column.getDataType() == DataType.NVarchar) {
                return true;
            }
        }
        if (oldColumn.getDataType() == DataType.DateTime) {
            if (column.getDataType() == DataType.TimeStamp) {
                return true;
            }
        }
        if (oldColumn.getDataType() == DataType.SmallInt) {
            if (column.getDataType() == DataType.Int) {
                return true;
            }
        }
        return false;
    }

    /**
     * 对比两个索引是否一致
     *
     * @param index
     * @param oldIndex
     * @return
     */
    private boolean compareIndexs(DatabaseObjectIndex index, DatabaseObjectIndex oldIndex) {
        if (!compareStr(index.getCode(), oldIndex.getCode())) {
            return false;
        }
        if (!compareStr(index.getName(), oldIndex.getName())) {
            return false;
        }
        if (!compareStr(index.getDescription(), oldIndex.getDescription())) {
            return false;
        }
        if (!compareStr(index.getVersion(), oldIndex.getVersion())) {
            return false;
        }
        if (index.isIfPrimary_Key() != oldIndex.isIfPrimary_Key()) {
            return false;
        }
        if (index.isCluster_Constraint() != oldIndex.isCluster_Constraint()) {
            return false;
        }
        if (index.isUnique_Constraint() != oldIndex.isUnique_Constraint()) {
            return false;
        }
        List<DatabaseObjectColumn> indexColumn = index.getColumns();
        List<DatabaseObjectColumn> oldIndexColumn = oldIndex.getColumns();
        if ((indexColumn == null && oldIndexColumn != null) || (indexColumn != null && oldIndexColumn == null)) {
            return false;
        }
        if (indexColumn != null && oldIndexColumn != null) {
            if (indexColumn.size() != oldIndexColumn.size()) {
                return false;
            }
            DatabaseObjectColumn columnTemp = null;
            for (DatabaseObjectColumn column : indexColumn) {
                columnTemp = existsColumn(column, oldIndexColumn);
                if (columnTemp == null) {
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * 判断某一索引，在索引集合中是否存在
     *
     * @param index
     * @param indexs
     * @return
     */
    private DatabaseObjectIndex existsIndex(DatabaseObjectIndex index, List<DatabaseObjectIndex> indexs) {
        for (DatabaseObjectIndex databaseObjectIndex : indexs) {
            if (databaseObjectIndex.getId().equals(index.getId())) {
                return databaseObjectIndex;
            }
        }
        return null;
    }

    /**
     * 比较字符串是否相等
     *
     * @param str1
     * @param str2
     * @return
     */
    private boolean compareStr(String str1, String str2) {
        if ((str1 == null && str2 != null) || (str1 != null && str2 == null)) {
            return false;
        }
        if (str1 != null && str2 != null) {
            return str1.equals(str2);
        }
        return true;
    }

    private boolean compareRuleStrategy(List<DimensionStrategyWithOrder> newDimStrategy, List<DimensionStrategyWithOrder> oldDimStrategy) {
        if (newDimStrategy.size() != oldDimStrategy.size()) {
            return false;
        }
        for (DimensionStrategyWithOrder strategy : newDimStrategy) {
            DimensionStrategyWithOrder oldStrategy = oldDimStrategy.stream().filter(item ->
                    item.getDimensionEntity().getId().equals(strategy.getDimensionEntity().getId()) &&
                            item.getDimensionEntity().getCode().equals(strategy.getDimensionEntity().getCode())).findFirst().orElse(null);
            if (oldStrategy == null) {
                return false;
            }
            if (oldStrategy.getOrder() != strategy.getOrder()) {
                return false;
            }
        }
        return true;
    }

    /**
     * 获取当前数据库连接信息
     *
     * @return
     */
    public DBInfo getCurrentDbInfo() {
        EntityManager entityManager = SpringBeanUtils.getBean(EntityManager.class);
        SessionImpl session = (SessionImpl) entityManager.getDelegate();
        JdbcConnectionAccess jdbcConnectionAccess = session.getJdbcConnectionAccess();
        HikariDataSource hikariDataSource = null;
        String tenantIdentifier = session.getTenantIdentifier();
        Object multiTenantConnectionProvider = getClassPropertyValue((ContextualJdbcConnectionAccess) jdbcConnectionAccess, "connectionProvider");
        Object dataSource = InvokeService.invokeProtectedMethod(((AbstractDataSourceBasedMultiTenantConnectionProviderImpl) multiTenantConnectionProvider), "selectDataSource", tenantIdentifier);
        if (dataSource instanceof HikariDataSource) {
            hikariDataSource = (HikariDataSource) dataSource;
        } else if (dataSource instanceof DataSourceProxy) {
            //兼容seata数据源代理
            DataSourceProxy dataSourceProxy = (DataSourceProxy) dataSource;
            hikariDataSource = (HikariDataSource) dataSourceProxy.getTargetDataSource();
        }
        DBInfo dbInfo = new DBInfo();
        String url = hikariDataSource.getJdbcUrl();
        dbInfo.setUrl(url);
        dbInfo.setPassWord(hikariDataSource.getPassword());
        dbInfo.setUserName(hikariDataSource.getUsername());
        String s = url.substring(url.indexOf(":") + 1);
        String t = s.substring(0, s.indexOf(":"));
        if (t.equals("dm")) {
            dbInfo.setDbType(DbType.DM);
        } else if (t.equals("postgresql")) {
            dbInfo.setDbType(DbType.PgSQL);
        } else if (t.equals("oracle")) {
            dbInfo.setDbType(DbType.Oracle);
        } else if (t.equals("sqlserver")) {
            dbInfo.setDbType(DbType.SQLServer);
            String dbName = url.split("database=")[1];
            if (dbName.contains(";")) {
                dbName = dbName.split(";")[0];
            }
            dbInfo.setDbName(dbName);
        } else if (t.equals("highgo")) {
            dbInfo.setDbType(DbType.HighGo);
        } else if (t.equals("mysql")) {
            dbInfo.setDbType(DbType.MySQL);
            String mysqlUrl = url.split("[?]")[0];
            String dbName = mysqlUrl.substring(mysqlUrl.lastIndexOf("/") + 1);
            dbInfo.setDbName(dbName);
        } else if (t.equals("oscar")) {
            dbInfo.setDbType(DbType.Oscar);
        } else if (t.equals("kingbase8")) {
            dbInfo.setDbType(DbType.Kingbase);
        } else if (t.equals("db2")) {
            dbInfo.setDbType(DbType.DB2);
        } else if (t.equals("opengauss")) {
            dbInfo.setDbType(DbType.OpenGauss);
        } else if (t.equals("gbase8s")) {
            dbInfo.setDbType(DbType.GBase8s);
        } else if (t.equals("gbase8c")) {
            dbInfo.setDbType(DbType.GBase8c);
        }

        return dbInfo;
    }

    private static Object getClassPropertyValue(Object entity, String propertyName) {
        Object value = null;
        try {
            Class<?> clazz = entity.getClass();
            Field field = clazz.getDeclaredField(propertyName);
            field.setAccessible(true);
            value = field.get(entity);
            return value;
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return value;
    }

    /**
     * 获取系统中的表
     *
     * @param db db
     * @return 表名
     */
    public List<String> getDbTables(DBInfo db) {
        String sql = null;
        if (db.getDbType() == DbType.Oracle || db.getDbType() == DbType.DM || db.getDbType() == DbType.Oscar) {
            sql = "select table_name from user_tables";
        } else if (db.getDbType() == DbType.PgSQL || db.getDbType() == DbType.HighGo || db.getDbType() == DbType.OpenGauss
                || db.getDbType() == DbType.GBase8s || db.getDbType() == DbType.GBase8c) {
            sql = "select tablename from pg_tables where lower(schemaname)='" + db.getUserName().toLowerCase() + "'";
        } else if (db.getDbType() == DbType.MySQL) {
            sql = "select TABLE_NAME from information_schema.TABLES where TABLE_TYPE='BASE TABLE' and LOWER(TABLE_SCHEMA)='" + db.getDbName().toLowerCase() + "'";
        } else if (db.getDbType() == DbType.SQLServer) {
            sql = "select name from sysObjects  where xtype='U'";
        } else if (db.getDbType() == DbType.Kingbase) {
            sql = "select table_name from user_tables";
        } else if (db.getDbType() == DbType.DB2) {
            sql = "SELECT TABNAME FROM SYSCAT.TABLES WHERE TABSCHEMA='" + db.getUserName().toUpperCase() + "'";
        } else {
            return new ArrayList<>();
        }
        List<String> tables = new ArrayList<>();
        GspDatabase gspDatabase = GspDbFactory.getDatabase(db);
        ResultSet resultSet = null;
        String tableName = null;
        try {
            resultSet = gspDatabase.executeResultSet(sql);
            if (resultSet != null) {
                while (resultSet.next()) {
                    tableName = resultSet.getString(1);
                    tables.add(tableName);
                }
            }
        } catch (Exception e) {
            throw new RuntimeException("获取数据库表时出错:", e);
        } finally {
            if (resultSet != null) {
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            gspDatabase.close();
        }
        return tables;
    }


    /**
     * 获取系统中的表
     *
     * @param db db
     * @return 表名
     */
    public List<String> getDbTables(DBInfo db, List<String> tableNames) {
        String sql = null;
        String whereSql = null;
        if (db.getDbType() == DbType.Oracle || db.getDbType() == DbType.DM || db.getDbType() == DbType.Oscar) {
            sql = "select table_name from user_tables";
            whereSql = " where table_name in";
        } else if (db.getDbType() == DbType.PgSQL || db.getDbType() == DbType.HighGo || db.getDbType() == DbType.OpenGauss) {
            sql = "select tablename from pg_tables where lower(schemaname)='" + db.getUserName().toLowerCase() + "'";
            whereSql = " and tablename in";
        } else if (db.getDbType() == DbType.MySQL) {
            sql = "select TABLE_NAME from information_schema.TABLES where TABLE_TYPE='BASE TABLE' and LOWER(TABLE_SCHEMA)='" + db.getDbName().toLowerCase() + "'";
            whereSql = " and TABLE_NAME in";
        } else if (db.getDbType() == DbType.SQLServer) {
            sql = "select name from sysObjects  where xtype='U'";
            whereSql = " and LOWER(name) in";
        } else if (db.getDbType() == DbType.Kingbase) {
            sql = "select table_name from user_tables";
            whereSql = " where LOWER(table_name) in";
        } else if (db.getDbType() == DbType.DB2) {
            sql = "SELECT TABNAME FROM SYSCAT.TABLES WHERE TABSCHEMA='" + db.getUserName().toUpperCase() + "'";
            whereSql = " and TABNAME IN";
        } else {
            return new ArrayList<>();
        }
        if(tableNames!=null && tableNames.size()>0){
            String inSql = "(";
            int count=0;
            for (String tname : tableNames) {
                if(DbType.Oracle.equals(db.getDbType()) || DbType.Oscar.equals(db.getDbType()) || DbType.DB2.equals(db.getDbType()) || DbType.DM.equals(db.getDbType())){
                    tname = tname.toUpperCase();
                }else if(DbType.PgSQL.equals(db.getDbType())|| DbType.HighGo.equals(db.getDbType()) || DbType.MySQL.equals(db.getDbType()) || DbType.OpenGauss.equals(db.getDbType()) || DbType.SQLServer.equals(db.getDbType())|| DbType.Kingbase.equals(db.getDbType())){
                    tname = tname.toLowerCase();
                }
                inSql = inSql + "'" + tname + "',";
            }
            inSql = inSql.substring(0, inSql.length() - 1);
            inSql = inSql + ")";
            sql = sql +whereSql+inSql;
        }
        List<String> tables = new ArrayList<>();
        GspDatabase gspDatabase = GspDbFactory.getDatabase(db);
        ResultSet resultSet = null;
        String tableName = null;
        try {
            resultSet = gspDatabase.executeResultSet(sql);
            if (resultSet != null) {
                while (resultSet.next()) {
                    tableName = resultSet.getString(1);
                    tables.add(tableName);
                }
            }
        } catch (Exception e) {
            throw new RuntimeException("获取数据库表时出错:", e);
        } finally {
            if (resultSet != null) {
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            gspDatabase.close();
        }
        return tables;
    }

    /**
     * 获取系统中临时表名
     *
     * @param db db
     * @return 表名
     */
    public static String tempTableIsExist(DBInfo db, String tableName) {
        String sql = "";
        if (db.getDbType() == DbType.Oracle || db.getDbType() == DbType.DM || db.getDbType() == DbType.Oscar) {
            sql = "select OBJECT_NAME from ALL_OBJECTS where temporary = 'Y' and OBJECT_NAME = '"+tableName.toUpperCase()+"'";
        } else if (db.getDbType() == DbType.PgSQL || db.getDbType() == DbType.HighGo || db.getDbType() == DbType.OpenGauss
                || db.getDbType() == DbType.GBase8s || db.getDbType() == DbType.GBase8c) {
            sql = "select tablename from (select to_regclass('"+tableName.toLowerCase()+"') as tablename) t where tablename is not null";
        } else if (db.getDbType() == DbType.MySQL) {
            return "";
        } else if (db.getDbType() == DbType.SQLServer) {
            sql = "select object_id(N'tempdb.."+tableName+"',N'U') as id";
        } else if (db.getDbType() == DbType.Kingbase) {
            sql = "select 1 from sys_tables where tablename = '"+tableName.toLowerCase()+"'";
        } else if (db.getDbType() == DbType.DB2) {
            return "";
        } else {
            return "";
        }
        return sql;
    }

    /**
     * 判断表中字段是否存在
     *
     * @param db    数据库连接
     * @param table 表名
     * @param filed 字段名
     * @return 是否
     */
    public boolean isFiledExist(DBInfo db, String table, String filed) {
        String sql = null;
        if (db.getDbType() == DbType.Oracle || db.getDbType() == DbType.DM || db.getDbType() == DbType.Oscar) {
            sql = "SELECT COUNT(1) FROM USER_TAB_COLS WHERE COLUMN_NAME = '" + filed.toUpperCase() + "' AND TABLE_NAME ='" + table.toUpperCase() + "'";
        } else if (db.getDbType() == DbType.PgSQL || db.getDbType() == DbType.HighGo || db.getDbType() == DbType.OpenGauss
                || db.getDbType() == DbType.GBase8s || db.getDbType() == DbType.GBase8c) {
            sql = "SELECT COUNT(1) FROM INFORMATION_SCHEMA.COLUMNS WHERE LOWER(TABLE_NAME) = '" + table.toLowerCase() + "' AND LOWER(COLUMN_NAME) = '" + filed.toLowerCase() + "' AND LOWER(TABLE_SCHEMA) = '" + db.getUserName().toLowerCase() + "'";
        } else if (db.getDbType() == DbType.MySQL) {
            sql = "SELECT COUNT(1) FROM information_schema.columns WHERE table_name='" + table.toLowerCase() + "' AND column_name='" + filed.toLowerCase() + "' AND TABLE_SCHEMA = '" + db.getDbName().toLowerCase() + "'";
        } else if (db.getDbType() == DbType.SQLServer) {
            sql = "SELECT COUNT(1) FROM SYS.SYSCOLUMNS A WHERE A.ID = OBJECT_ID('" + table + "') AND A.NAME = '" + filed + "'";
        } else if (db.getDbType() == DbType.Kingbase) {
            sql = "SELECT COUNT(1) FROM USER_TAB_COLS WHERE LOWER(COLUMN_NAME) = '" + filed.toLowerCase() + "' AND LOWER(TABLE_NAME) ='" + table.toLowerCase() + "'";
        } else if (db.getDbType() == DbType.DB2) {
            sql = "SELECT COUNT(1) FROM SYSCAT.COLUMNS WHERE TABNAME = '" + table.toUpperCase() + "' AND COLNAME ='" + filed.toUpperCase() + "'";
        }
        GspDatabase gspDatabase = GspDbFactory.getDatabase(db);
        ResultSet resultSet = null;
        try {
            resultSet = gspDatabase.executeResultSet(sql);
            if (resultSet != null) {
                while (resultSet.next()) {
                    return (!"0".equals(resultSet.getString(1)));
                }
            }
        } catch (Exception e) {
            throw new RuntimeException("判断表中字段是否存在出错:", e);
        } finally {
            if (resultSet != null) {
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            gspDatabase.close();
        }
        return false;
    }

    public Map<String, List<String>> getDefaultDimensionInfo(DBInfo db) {
        //获取默认的年度维度集合，以fiyear表中数据为准（解决FA、LS删除检查问题）
        Map<String, List<String>> dimensionInfo = new HashMap<>();
        List<String> list = getAllYear(db);
        dimensionInfo.put("FIYear", list);
        return dimensionInfo;
    }

    private List<String> getAllYear(DBInfo db) {
        String vsSql = "select year from FIYear";
        List<String> list = new ArrayList<>();
        ResultSet result = null;
        GspDatabase gspDatabase = GspDbFactory.getDatabase(db);
        try {
            result = gspDatabase.executeResultSet(vsSql);
            if (result != null) {
                while (result.next()) {
                    String year = result.getString(1);
                    list.add(year);
                }
            }
            //去重
            list = list.stream().distinct().collect(Collectors.toList());
            return list;
        } catch (Exception e) {
            throw new RuntimeException("获取fiYear中所有年度出错：" + e.getMessage(), e);
        } finally {
            if (result != null) {
                try {
                    result.close();
                } catch (SQLException e) {
                }
            }
            gspDatabase.close();
        }
    }

    private boolean isExistTable(List<String> tables, String table) {
        for (String obj : tables) {
            if (obj.equalsIgnoreCase(table)) {
                return true;
            }
        }
        return false;
    }

    public static List<String> getLanguages() {
        if (languages == null) {
            languages = new ArrayList<>();
            languages.add("_CHS");
            languages.add("_EN");
            languages.add("_CHT");
            languages.add("_ES");
            languages.add("_PT");
        }
        return languages;
    }

    public static void addLanguages(List<String> newLanguages) {
        if (languages == null) {
            languages = new ArrayList<>();
            languages.add("_CHS");
            languages.add("_EN");
            languages.add("_CHT");
            languages.add("_ES");
            languages.add("_PT");
        }
        for (String language : newLanguages) {
            if (languages.contains(language)) {
                continue;
            }
            languages.add(language);
        }
    }
}
